﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using Kinect.Framework;
using Kinect.Framework.Controls;
using Kinect.Framework.Interfaces;

namespace Kinect.Framework.Lib
{
    public static class VisualTreeHelpers
    {
        public static DependencyObject FirstVisualChild(UIElement visual)
        {
            if (visual == null) return null;
            if (VisualTreeHelper.GetChildrenCount(visual) == 0) return null;
            return VisualTreeHelper.GetChild(visual, 0);
        }
        public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
        {
            if (obj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                    if (child != null && child is T)
                        return (T)child;
                    else
                    {
                        T childOfChild = FindVisualChild<T>(child);
                        if (childOfChild != null)
                            return childOfChild;
                    }
                }
            }

            return null;
        }
        public static List<T> FindVisualChilds<T>(DependencyObject obj) where T : DependencyObject
        {
            var data = new List<T>();
            if (obj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                    if (child != null && child is T)
                        data.Add((T)child);
                    else
                    {
                        List<T> childOfChild = FindVisualChilds<T>(child);
                        if (childOfChild != null)
                            data.AddRange(childOfChild);
                    }
                }
                return data;
            }

            return null;
        }
        public static List<T> FindVisualChildsWithAttachedProperty<T>(DependencyObject obj) where T : DependencyObject
        {
            var data = new List<T>();
            if (obj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                    if (child != null && child is T && KinectManipulation.GetIsSelectable((UIElement)child) == true)
                        data.Add((T)child);
                    else
                    {
                        List<T> childOfChild = FindVisualChildsWithAttachedProperty<T>(child);
                        if (childOfChild != null)
                            data.AddRange(childOfChild);
                    }
                }
                return data;
            }

            return null;
        }
        public static List<T> FindVisualChildsImplentingIKinectElement<T>(DependencyObject obj) where T : DependencyObject
        {
            var data = new List<T>();
            if (obj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                    if (child != null && child is T && child is IKinectElement)
                        data.Add((T)child);
                    else
                    {
                        List<T> childOfChild = FindVisualChildsImplentingIKinectElement<T>(child);
                        if (childOfChild != null)
                            data.AddRange(childOfChild);
                    }
                }
                return data;
            }

            return null;
        }

        public static T FindVisualParentWithAttachedProperty<T>(DependencyObject obj) where T : DependencyObject
        {
            if (obj != null)
            {
                DependencyObject parent = VisualTreeHelper.GetParent(obj);
                if (parent != null && parent is T && parent is IKinectElement)
                    return (T)parent;
                else
                {
                    T parentOfParent = FindVisualParentWithAttachedProperty<T>(parent);
                    if (parentOfParent != null)
                        return parentOfParent;
                }
            }
            return null;
        }
        public static T FindVisualParent<T>(DependencyObject obj) where T : DependencyObject
        {
            if (obj != null)
            {
                if (obj != null && obj is T)
                    return (T)obj;
                DependencyObject parent = VisualTreeHelper.GetParent(obj);
                if (parent != null && parent is T)
                    return (T)parent;
                else
                {
                    T parentOfParent = FindVisualParent<T>(parent);
                    if (parentOfParent != null)
                        return parentOfParent;
                }
            }
            return null;
        }
    }
    /// <summary>
    /// Couple of simple helpers for walking the visual tree
    /// </summary>
    static class TreeHelpers
    {
        /// <summary>
        /// Gets the ancestors of the element, up to the root
        /// </summary>
        /// <param name="node">The element to start from</param>
        /// <returns>An enumerator of the ancestors</returns>
        public static IEnumerable<FrameworkElement> GetVisualAncestors(this FrameworkElement node)
        {
            FrameworkElement parent = node.GetVisualParent();
            while (parent != null)
            {
                yield return parent;
                parent = parent.GetVisualParent();
            }
        }

        /// <summary>
        /// Gets the visual parent of the element
        /// </summary>
        /// <param name="node">The element to check</param>
        /// <returns>The visual parent</returns>
        public static FrameworkElement GetVisualParent(this FrameworkElement node)
        {
            return VisualTreeHelper.GetParent(node) as FrameworkElement;
        }
    }
}
